package com.hycc.base;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;

/*
* 求和 1~ 10_0000_0000
* */
public class ForkJoinDemo {
    /*
    * 使用 ForkJoin
    * 1 使用 ForkJoinPool
    * 2 计算任务 ForkJoinPool.execute(ForkJoinTask task)
    * 3 RecursiveTask 递归任务 和 RecursiveAction 递归事件
    *
    * */
    public static void main(String[] args) {
        long start=0L;
        long end=10_0000_0000L;
        long begin=0;
        long over=0;

        begin =System.currentTimeMillis();
        System.out.println(test1(start, end));
        over = System.currentTimeMillis();
        System.out.println("test1 用时："+(over-begin));

        begin =System.currentTimeMillis();
        test2(start, end);
        over = System.currentTimeMillis();
        System.out.println("test2 用时："+(over-begin));

        begin =System.currentTimeMillis();
        System.out.println(test3(start, end));
        over = System.currentTimeMillis();
        System.out.println("test3 用时："+(over-begin));

    }

    public static long test1(long start,long end){
        long sum =0L;
        for (long i = start; i <= end; i++) {
            sum += i;
        }
        return sum;
    }

    /*
    * 使用ForkJoin
    * */
    public static void test2(long start, long end){
        //创建ForkJoinPool
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        //创建ForkJoin 任务
        MyForkJoin task = new MyForkJoin(start, end);
        /*//submit 提交任务到分支合并池 submit是异步的
        ForkJoinTask<Long> taskHandler = forkJoinPool.submit(task);
        //提交的ForkJoin任务，使用get()方法取得返回值
        try {
            //ForkJoinTask的 get()方法会阻塞等待
            long result = taskHandler.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }*/

        //forkJoinPool.execute() 方法没有返回值
        forkJoinPool.execute(task);
        try {
            //task的 get()方法会阻塞等待
            long result = task.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    //流式计算
    public static long test3(long start, long end){
        //Stream.range()是前闭后开的 [2,5) 可以取到 2,3,4
        return LongStream.range(start,end+1).parallel().reduce(0,Long::sum);
    }
}

//需要一个实现类 继承 RecursiveTask<V> 返回V
class MyForkJoin extends RecursiveTask<Long>{
    private long start;
    private long end;
    private long sum ;
    private int count;
    //临界值
    private Long temp = 1_0000_0000L;

    public MyForkJoin(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        //计算任务
        if(end-start<=temp){
            /*//普通计算
            for (Long i = start; i <= end; i++) {
                sum+=i;
            }*/
            //流式计算
            sum = LongStream.range(start,end+1).parallel().reduce(0,Long::sum);
        }else{
            /*//拆分任务
            count = new Long((start+end)/temp+(((start + end) % temp == 0) ? 0 : 1)).intValue();

            MyForkJoin[] task = new MyForkJoin[count];
            //拆分任务，并将任务压入队列
            for (int i = 0; i < count; i++) {
                task[i] = new MyForkJoin(start+temp*i+(i==0?0:1),((count-1==i)?end:start+temp*(i+1)));
                task[i].fork(); //将任务压入队列
            }
            //合并计算结果
            for (int i = 0; i < count; i++) {
                sum+=task[i].join();
            }*/

            //拆分任务
            count = new Long((start+end)/temp+(((start + end) % temp == 0) ? 0 : 1)).intValue();

            //拆分任务，并将任务压入队列
            List<MyForkJoin> list = new ArrayList<>(count);
            for (int i = 0; i < count; i++) {
                list.add(new MyForkJoin(start+temp*i+(i==0?0:1),((count-1==i)?end:start+temp*(i+1))));
                list.get(i).fork();
            }

            //合并计算结果
            for (MyForkJoin myForkJoin : list) {
                sum+=myForkJoin.join();
            }
        }

        return sum;
    }
}